package com.hy.generator.utils;

import com.hy.generator.common.exception.BusinessException;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;

/**
 * Freemarker 模板生成工具类
 *
 * @author User
 */
@Slf4j
public class FreeMarkerUtil {


    private static final Configuration configuration;
    private static final String linuxBasePath = "templates";
    private static final String winBasePath;

    static {
        try {
            configuration = new Configuration(Configuration.VERSION_2_3_34);
            configuration.setDefaultEncoding("UTF-8");
            configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
            configuration.setNumberFormat("computer");

            if (isWindows()) {
                File templateDir = new File(ResourceUtils.getURL("classpath:templates").getFile());
                configuration.setDirectoryForTemplateLoading(templateDir);
                winBasePath = templateDir.getAbsolutePath();
            } else {
                configuration.setClassForTemplateLoading(FreeMarkerUtil.class, "/" + linuxBasePath);
                winBasePath = "";//不会使用
            }

        } catch (IOException e) {
            throw new BusinessException(e.getMessage());
        }


    }


    /**
     * FreeMarker 模板固定写法
     *
     * @param templatePath
     * @param filePath
     */
    public static void process(String templatePath, Object config, String filePath) {
        Writer writer = null;
        try {
            File file = new File(filePath);
            file.getParentFile().mkdirs();

            writer = new FileWriter(filePath);
            Template template = configuration.getTemplate(templatePath);


            template.process(config, writer);
            writer.flush();
            writer.close();
        } catch (IOException | TemplateException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }


    }

    /**
     * @param templatePath 模板文件绝对路径
     * @param outBasePath  输出目录基本路径
     * @param classify_dir 模板文件分类的目录，输出时去掉
     * @param replace      需要替换文件路径
     * @return
     */
    public static String calculateOutputPath(String templatePath, String outBasePath, String classify_dir, Map<String, String> replace) {
        // 替换路径中的目录结构
        final StringBuilder pathBuilder = new StringBuilder(templatePath);
        replace.forEach((key, value) ->
                pathBuilder.replace(0, pathBuilder.length(), pathBuilder.toString().replace(key, value))
        );
        // 去掉模板文件分类目录
        templatePath = pathBuilder.substring(classify_dir.length() + 1);
        // 构建最终输出路径
        String outputPath = outBasePath + File.separator + templatePath;

        // 替换文件扩展名
        if (outputPath.endsWith(".ftl")) {
            outputPath = outputPath.substring(0, outputPath.length() - 4);
        }

        return outputPath;
    }


    public static List<String> findTemplateFilePaths(String dirName) {
        if (isWindows()) {
            return findWinTemplateFilePaths(dirName);
        } else {
            return findLinuxTemplateFilePaths(dirName);
        }
    }

    private static List<String> findWinTemplateFilePaths(String dirName) {
        List<String> templateFiles = new ArrayList<>();
        File templateDir = new File(winBasePath + File.separator + dirName);

        if (!templateDir.exists() || !templateDir.isDirectory()) {
            throw new IllegalArgumentException("模板目录不存在或无效: " + winBasePath);
        }

        // 递归扫描目录
        scanDirectory(templateDir, templateFiles);

        return templateFiles;
    }

    private static List<String> findLinuxTemplateFilePaths(String dirName) {
        String resourceDir = linuxBasePath + "/" + dirName;
        List<String> templateFiles = new ArrayList<>();
        try {
            //必须jar包运行
            scanJarResources(resourceDir, templateFiles);
        } catch (Exception e) {
            throw new IllegalArgumentException("无法读取模板目录: " + resourceDir, e);
        }
        return templateFiles;
    }

    private static void scanJarResources(String resourceDir, List<String> result) throws IOException {
        ClassLoader classLoader = FreeMarkerUtil.class.getClassLoader();
        java.net.URL url = classLoader.getResource(resourceDir);
        if (url == null) {
            throw new IllegalArgumentException("模板目录不存在: " + resourceDir);
        }

        // 打开 JAR 文件连接
        java.util.jar.JarFile jar = ((java.net.JarURLConnection) url.openConnection()).getJarFile();
        Enumeration<JarEntry> entries = jar.entries();

        while (entries.hasMoreElements()) {
            java.util.jar.JarEntry entry = entries.nextElement();
            String name = entry.getName();
            if (name.startsWith(resourceDir) && name.endsWith(".ftl")) {
                result.add(name.substring(linuxBasePath.length() + 1));
            }
        }
    }

    private static void scanDirectory(File dir, List<String> result) {
        File[] files = dir.listFiles();
        if (files == null) return;

        for (File file : files) {
            if (file.isDirectory()) {
                scanDirectory(file, result);
            } else if (file.getName().endsWith(".ftl")) {
                result.add(file.getAbsolutePath().substring(winBasePath.length() + 1));
            }
        }
    }


    public static String toPascalCase(String input) {
        if (input == null || input.isEmpty()) {
            return input;
        }

        StringBuilder result = new StringBuilder();
        boolean capitalizeNext = false;

        // 统一处理首字母大写
        result.append(Character.toUpperCase(input.charAt(0)));

        for (int i = 1; i < input.length(); i++) {
            char c = input.charAt(i);

            if ((c == '-' || c == '_')) {
                capitalizeNext = true;
            } else {
                if (capitalizeNext) {
                    result.append(Character.toUpperCase(c));
                    capitalizeNext = false;
                } else {
                    result.append(c);
                }
            }
        }

        return result.toString();
    }

    public static String toCamelCase(String input) {
        if (input == null || input.isEmpty()) {
            return input;
        }
        StringBuilder builder = new StringBuilder();
        boolean nextUpperCase = false;
        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);
            if ((c == '-' || c == '_')) {
                nextUpperCase = true;
            } else {
                if (nextUpperCase) {
                    builder.append(Character.toUpperCase(c));
                    nextUpperCase = false;
                } else {
                    builder.append(Character.toLowerCase(c));
                }
            }
        }
        return builder.toString();
    }

    public static boolean isWindows() {
        return System.getProperty("os.name").toLowerCase().contains("win");
    }
}
